package com.googlecode.messwertepi.configuration;

import com.googlecode.messwertepi.util.GpioPin;
import gnu.io.SerialPort;
import org.apache.commons.configuration.HierarchicalConfiguration;

/**
 * Created by eike on 25.06.14.
 */
public class XMLConfiguration implements Configuration
{
    private HierarchicalConfiguration configuration;

    public XMLConfiguration(HierarchicalConfiguration configuration)
    {
        this.configuration = configuration;
    }

    @Override
    public String getPrinterTempFile() {
        return getString("printer.tempFile");
    }

    @Override
    public int getGuiWidth() throws ConfigurationException
    {
        return getInt("gui.width");
    }

    @Override
    public int getGuiHeight() throws ConfigurationException
    {
        return getInt("gui.height");
    }

    @Override
    public GpioPin getPinDown() {
        return getGpioPin(getString("input.down"));
    }

    @Override
    public GpioPin getPinUp() {
        return getGpioPin(getString("input.up"));
    }

    @Override
    public GpioPin getPinConfirm() {
        return getGpioPin(getString("input.confirm"));
    }

    @Override
    public GpioPin getPinPrint() {
        return getGpioPin(getString("input.print"));
    }

    @Override
    public String getSerialPortDevice() {
        return getString("serialPort.device");
    }

    @Override
    public int getSerialPortBaudRate() {
        return getInt("serialPort.baudRate");
    }

    @Override
    public int getSerialPortDataBits() {
        String value = getString("serialPort.dataBits");
        switch (value) {
            case "DATABITS_5": return SerialPort.DATABITS_5;
            case "DATABITS_6": return SerialPort.DATABITS_6;
            case "DATABITS_7": return SerialPort.DATABITS_7;
            case "DATABITS_8": return SerialPort.DATABITS_8;
            default: throw new ConfigurationException("Unknown data bits");
        }
    }

    @Override
    public int getSerialPortStopBits() {
        String value = getString("serialPort.stopBits");
        switch (value) {
            case "STOPBITS_1": return SerialPort.STOPBITS_1;
            case "STOPBITS_2": return SerialPort.STOPBITS_2;
            case "STOPBITS_1_5": return SerialPort.STOPBITS_1_5;
            default: throw new ConfigurationException("Unknown stop bits");
        }
    }

    @Override
    public int getSerialPortParity() {
        String value = getString("serialPort.parity");
        switch (value) {
            case "PARITY_NONE": return SerialPort.PARITY_NONE;
            case "PARITY_ODD": return SerialPort.PARITY_ODD;
            case "PARITY_EVEN": return SerialPort.PARITY_EVEN;
            case "PARITY_MARK": return SerialPort.PARITY_MARK;
            case "PARITY_SPACE": return SerialPort.PARITY_SPACE;
            default: throw new ConfigurationException("Unknown parity");
        }
    }

    @Override
    public int getSerialPortFlowControl() {
        String value = getString("serialPort.flowControl");
        switch (value) {
            case "FLOWCONTROL_NONE": return SerialPort.FLOWCONTROL_NONE;
            case "FLOWCONTROL_RTSCTS_IN": return SerialPort.FLOWCONTROL_RTSCTS_IN;
            case "FLOWCONTROL_RTSCTS_OUT": return SerialPort.FLOWCONTROL_RTSCTS_OUT;
            case "FLOWCONTROL_XONXOFF_IN": return SerialPort.FLOWCONTROL_XONXOFF_IN;
            case "FLOWCONTROL_XONXOFF_OUT": return SerialPort.FLOWCONTROL_XONXOFF_OUT;
            default: throw new ConfigurationException("Unknown flow control mode");
        }

    }

    /**
     * This method returns the configuration value of the specified key
     * as an integer.
     *
     * @param key the key
     * @return the value as an integer
     * @throws ConfigurationException if the key is invalid, or the value is not an integer
     */
    private int getInt(String key) throws ConfigurationException
    {
        String value = getString(key);
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException nfe) {
            throw new ConfigurationException("Failed to parse the configuration value", nfe);
        }
    }

    /**
     * This method returns the configuration value of the specified key
     * as a String.
     *
     * @param key the key
     * @return the value
     * @throws ConfigurationException if the key is invalid
     */
    private String getString(String key) throws ConfigurationException
    {
        if (!configuration.containsKey(key)) {
            throw new ConfigurationException("Unknown configuration key '" + key + "'");
        }

        return configuration.getString(key);
    }

    /**
     * Returns the GpioPin instance that belongs to the specified key.
     *
     * @param key the gpio pin
     * @return the GpioPin instance
     * @throws ConfigurationException if the key is invalid
     */
    private GpioPin getGpioPin(String key) throws ConfigurationException {
        try {
            return GpioPin.valueOf(key);
        } catch (IllegalArgumentException iae) {
            throw new ConfigurationException("Unknown GPIO Pin", iae);
        }
    }
}